/* SPDX-License-Identifier: GPL-2.0 */
#ifndef SEMINIX_MMZONE_H
#define SEMINIX_MMZONE_H

#include <utils/types.h>
#include <utils/list.h>
#include <seminix/cache.h>
#include <seminix/percpu.h>
#include <seminix/spinlock.h>

enum zone_type {
    ZONE_DMA,
    ZONE_NORMAL,
    __MAX_NR_ZONES,
};

#ifndef ASM_OFFSET_GENERATED

#include <generated/asm-offsets.h>

/* Free memory management - zoned buddy allocator.  */
#ifndef CONFIG_FORCE_MAX_ZONEORDER
#define MAX_ORDER 11
#else
#define MAX_ORDER CONFIG_FORCE_MAX_ZONEORDER
#endif
#define MAX_ORDER_NR_PAGES (1 << (MAX_ORDER - 1))

struct zone_min_pfn {
    phys_addr_t zone_pfn[MAX_NR_ZONES];
};

struct free_area {
    struct list_head	free_list;
    unsigned long		nr_free;
};

struct per_cpu_pages {
    int count;		/* number of pages in the list */
    int high;		/* high watermark, emptying needed */
    int batch;		/* chunk size for buddy add/remove */

    struct list_head lists;
};

struct per_cpu_pageset {
    struct per_cpu_pages pcp;
};

struct zone {
    struct pglist_data	*zone_pgdat;
    struct per_cpu_pageset __percpu *pageset;

    unsigned long zone_start_pfn;

    atomic_long_t managed_pages;

    const char  *name;

    int initialized;

    /* free areas of different sizes */
    struct free_area free_area[MAX_ORDER];

    /* Primarily protects free_area */
    spinlock_t lock;
} ____cacheline_internodealigned_in_smp;

typedef struct pglist_data {
    struct zone node_zones[MAX_NR_ZONES];
    unsigned long node_start_pfn;
} pg_data_t;

extern struct pglist_data node_data;
#define NODE_DATA()		(&node_data)

static inline bool zone_is_initialized(struct zone *zone)
{
    return zone->initialized;
}

static inline unsigned long zone_managed_pages(struct zone *zone)
{
    return (unsigned long)atomic_long_read(&zone->managed_pages);
}

#define for_each_order(order)   \
    for (order = 0; order < MAX_ORDER; order++)

#endif /* !ASM_OFFSET_GENERATED */
#endif /* !SEMINIX_MMZONE_H */
